﻿using System;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CRM.Models.Email;
using CRM.Models.Mailjet;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using EmailMarketing = CRM.Models.Email.EmailMarketing;

namespace CRM.Controllers
{
    [AllowAnonymous]
    [Route("[controller]")]
    public class Mailjet : ControllerBase
    {
        private readonly MyDbContext _dbContext;
        private readonly ILogger<Mailjet> _logger;
        public Mailjet(MyDbContext dbContext, ILogger<Mailjet> logger)
        {
            _dbContext = dbContext;
            _logger = logger;
        }
        /// <summary>
        /// 处理回调事件
        /// </summary>
        /// <returns></returns>
        [Route("[action]")]
        public async Task<IActionResult> Endpoint()
        {
            var reader = new StreamReader(Request.Body, Encoding.UTF8);
            var body = await reader.ReadToEndAsync().ConfigureAwait(false);
            _logger.LogDebug("Endpoint接口触发, 请求参数：{Response}", body);

            JToken response;
            try
            {
                response = JToken.Parse(body);
            }
            catch
            {
                _logger.LogCritical("请求异常: {Body}", body);
                return Problem();
            }
            
            if (response is JObject jObject)
            {
                return await Endpoint(jObject);
            }

            if (response is JArray jArray)
            {
                var flag = false;
                foreach (var token in jArray)
                {
                    var result = await Endpoint(token as JObject);
                    if (result is ObjectResult) flag = true;
                }

                return flag == false ? Ok() : Problem();
            }

            return Problem();
        }
        private async Task<IActionResult> Endpoint(JObject response)
        {
            // params from env,setting a security username and password,links:https://app.mailjet.com/account/triggers 
            // you can change this link online.(https://dev.mailjet.com/email/reference/webhook/#v3_post_eventcallbackurl)
            var authLock = "username:password";
            // 鉴权验证
            try
            {
                var authKey =
                    Encoding.UTF8.GetString(
                        Convert.FromBase64String(Request.Headers["Authorization"].ToString()[6..]));
                if (authKey != authLock)
                {
                    Console.WriteLine("非法调用");
                    return Problem();
                }
            }
            catch (Exception)
            {
                return Problem();
            }

            MailjetRequest request = default;
            try
            {
                request = response.ToObject<MailjetRequest>();
            }
            catch { }

            int webhookLogId;
            
            if (null == request)
            {
                _logger.LogCritical("json解析异常， 参数: {Response}", response);
                return Problem();
            }
            else
            {
                //存储WebhookLog
                var model = new WebhookLog {Data = response.ToString()};
                _dbContext.WebhookLog.Add(model);
                await  _dbContext.SaveChangesAsync();
                webhookLogId = model.Id;
            }
            
            // 测试消息
            if (request.MessageId == 0)
            {
                return Ok();
            }

            // 正确处理 缓存或存储当前数据，返回对应状态码。其他的交给队列处理，缓解数据库压力
            // 目前实现 直接交给数据库处理，数据库压力较大
            var flag = request.Event switch
            {
                "open" => await HandleOpen(request, response,webhookLogId),
                "click" => await HandleClick(request, response,webhookLogId),
                "bounce" => await HandleBounce(request, response,webhookLogId),
                "spam" => await HandleSpam(request, response,webhookLogId),
                "blocked" => await HandleBlocked(request, response,webhookLogId),
                "unsub" => await HandleUnsub(request, response,webhookLogId),
                "sent" => await HandleSent(request, response,webhookLogId),
                _ => false 
            };

            if (!flag)
            {
                return Problem();
            }

            // 业务处理
            return Ok();
        }
        private async Task<bool> HandleOpen(MailjetRequest request, JObject response,int webhookLogId)
        {
            var emailMarketingHistoryRecord = _dbContext.EmailSendHistory
                .FirstOrDefault(m => m.MessageID == request.MessageId);
 
            //todo: 已读 bit 位设为 1
            if (null == emailMarketingHistoryRecord)
            {
                _logger.LogWarning("营销任务数据异常，请求数据: {Request}", response.ToString());
                return false;
            }

            AddWebhookEventDetails(request, response, webhookLogId);

            emailMarketingHistoryRecord.Details |= (long) DetailsEnum.Open;
            // _dbContext.EmailMarketing.Where(m => m.Id == emailMarketingHistoryRecord.Source).Update(m => m.OpenNum+1);
            await _dbContext.Database.ExecuteSqlRawAsync(
                $"UPDATE {nameof(_dbContext.EmailMarketing)} SET {nameof(EmailMarketing.OpenNum)} = {nameof(EmailMarketing.OpenNum)} + 1 Where {nameof(EmailMarketing.Id)} = {emailMarketingHistoryRecord.Source}");
            //保存
            await _dbContext.SaveChangesAsync();
            return true;
        }
        private async Task<bool> HandleSent(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private async Task<bool> HandleUnsub(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private async Task<bool> HandleBlocked(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private async Task<bool> HandleSpam(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private async Task<bool> HandleBounce(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private async Task<bool> HandleClick(MailjetRequest request, JObject response,int webhookLogId)
        {
            await Task.Run(()=>{});
            return false;
        }
        private void AddWebhookEventDetails(MailjetRequest request,JObject response,int webhookLogId)
        {
            var modelWebhookEventDetails = new WebhookEventDetails
            {
                WebhookLogId = webhookLogId,
                Event = request.Event,
                Time = request.Time,
                Email = request.Email,
                MjCampaignId = request.MjCampaignId,
                MjContactId = request.MjContactId,
                CustomCampaign = request.CustomCampaign,
                MessageId = request.MessageId,
                CustomId = request.CustomId,
                Payload = request.Payload,
                Data = response.ToString()
            };
            _dbContext.WebhookEventDetails.Add(modelWebhookEventDetails);
        }
    }

    public class MailjetRequest
    {
        [JsonProperty("event")] public string Event { get; set; }
        [JsonProperty("time")] public int Time { get; set; }
        [JsonProperty("MessageID")] public long MessageId { get; set; }
        [JsonProperty("Message_GUID")] public string MessageGuid { get; set; }
        [JsonProperty("email")] public string Email { get; set; }
        [JsonProperty("mj_campaign_id")] public int MjCampaignId { get; set; }
        [JsonProperty("mj_contact_id")] public int MjContactId { get; set; }
        [JsonProperty("customcampaign")] public string CustomCampaign { get; set; }
        [JsonProperty("mj_message_id")] public string MjMessageId { get; set; }
        [JsonProperty("smtp_reply")] public string SmtpReply { get; set; }
        [JsonProperty("CustomID")] public string CustomId { get; set; }
        [JsonProperty("Payload")] public string Payload { get; set; }
        [JsonProperty("mj_list_id")] public string MjListId { get; set; }
        [JsonProperty("url")] public string Url { get; set; }
        [JsonProperty("ip")] public string Ip { get; set; }
        [JsonProperty("geo")] public string Geo { get; set; }
        [JsonProperty("agent")] public string Agent { get; set; }
        [JsonProperty("blocked")] public bool Blocked { get; set; }
        [JsonProperty("hard_bounce")] public bool HardBounce { get; set; }
        [JsonProperty("error_related_to")] public string ErrorRelatedTo { get; set; }
        [JsonProperty("error")] public string Error { get; set; }
        [JsonProperty("comment")] public string Comment { get; set; }
        [JsonProperty("source")] public string Source { get; set; }
    }
    
    
}